package ro.flashbite.game_engine.data
{
	import ro.flashbite.game_engine.data.intefaces.IPlayerData;
	import ro.flashbite.game_engine.data.intefaces.IScoreObject;
	import ro.flashbite.interfaces.IDestroyable;
	
	/**
	 * Holds all important data about one player
	 * 
	 * v 1.0
	 *  
	 * @author Adrian Barbu
	 */	
	public final class PlayerData implements IPlayerData, IDestroyable
	{
		private static const MAX_SCORES						:	uint = 10; //maximum scores saved here
		
		private static const SERIALIZED_PLAYER_NAME			:	String = "playerName";
		private static const SERIALIZED_CHARACTER_NAME		:	String = "characterName";
		private static const SERIALIZED_DIFFICULTY			:	String = "difficulty";
		private static const SERIALIZED_SCORES				:	String = "scores";
		private static const SERIALIZED_CHARACTERS_UNLOCKED	:	String = "charactersUnlocked";
		private static const SERIALIZED_LOCATION			:	String = "location"
		private static const SERIALIZED_LOCATIONS_UNLOCKED	:	String = "locationsUnlocked";
		
		private var _playerName			:	String;
		private var _characterName		:	String;
		private var _difficulty			:	uint;
		private var _scores				:	Vector.<IScoreObject>;
		private var _charactersUnlocked	:	Vector.<String>;
		private var _location			:	String;
		private var _locationsUnlocked	:	Vector.<String>;
		
		// ================================================================================================================================
		// CONSTRUCTOR
		// ================================================================================================================================
		
		public function PlayerData(playerName:String = null, characterName:String = null, difficulty:uint = 1, scores:Vector.<IScoreObject> = null,
								   charactersUnlocked:Vector.<String> = null, locationsUnlocked:Vector.<String> = null)
		{
			_constructor(playerName, characterName, difficulty, scores, charactersUnlocked, locationsUnlocked);
		}
		private function _constructor(playerName:String, characterName:String, difficulty:uint, scores:Vector.<IScoreObject>,
									  charactersUnlocked:Vector.<String>, locationsUnlocked:Vector.<String>):void
		{
			this.playerName = playerName;
			this.characterName = characterName;
			this.difficulty = difficulty;
			this.scores = scores;
			this.charactersUnlocked = charactersUnlocked;
			this.locationsUnlocked = locationsUnlocked;
		}
		
		// ================================================================================================================================
		// IPlayerData
		// ================================================================================================================================
		
		public function get playerName()					: String { return _playerName; 		 }
		public function set playerName(playerName:String)	: void 	 { _playerName = playerName; }
		
		public function get characterName()					: String { return _characterName; 	 }
		public function set characterName(charName:String)	: void 	 {_characterName = charName; }
		
		public function get difficulty()					: uint { return _difficulty; }
		public function set difficulty(diff:uint)			: void {_difficulty = diff;  }
		
		public function get scores()							 : Vector.<IScoreObject> { return _scores; 									  							}
		public function set scores(scores:Vector.<IScoreObject>) : void 			 	 { _scores = (scores) ? scores : new Vector.<IScoreObject>(); cleanupScores(); 	}
		public function addScoreObject(scoreObj:IScoreObject)	 : void 				 { _scores.push(scoreObj); cleanupScores();			  	  						}
		
		public function get charactersUnlocked()					  	 : Vector.<String> { return _charactersUnlocked; 												  }
		public function set charactersUnlocked(chars:Vector.<String>) 	 : void 		   { _charactersUnlocked = (chars) ? chars : new Vector.<String>(); 			  }
		public function addCharacterUnlocked(char:String)				 : void			   { if (_charactersUnlocked.indexOf(char) == -1) _charactersUnlocked.push(char); }
		
		public function get location()							: String { return _location; 	 }
		public function set location(location:String)			: void	 { _location = location; }
		
		public function get locationsUnlocked()							 : Vector.<String> { return _locationsUnlocked; 										  				}
		public function set locationsUnlocked(locations:Vector.<String>) : void 		   { _locationsUnlocked = (locations) ? locations : new Vector.<String>(); 				}
		public function addLocationUnlocked(location:String)			 : void			   { if (_locationsUnlocked.indexOf(location) == -1) _locationsUnlocked.push(location); }
		
		// ================================================================================================================================
		// ISerializable
		// ================================================================================================================================
		
		public static function serialize(data:PlayerData):Object
		{
			var obj:Object = {};
			
			obj[SERIALIZED_PLAYER_NAME] = data.playerName;
			obj[SERIALIZED_CHARACTER_NAME] = data.characterName;
			obj[SERIALIZED_DIFFICULTY] = data.difficulty;
			
			var dataToSave:Array,
				value:*;
			
			dataToSave = [];
			for each (value in data.scores) {
				dataToSave.push(value);
			}
			obj[SERIALIZED_SCORES] = dataToSave.concat(); //clone
				
			dataToSave = [];
			for each (value in data.charactersUnlocked) {
				dataToSave.push(value);
			}
			obj[SERIALIZED_CHARACTERS_UNLOCKED] = dataToSave.concat(); //clone
			
			obj[SERIALIZED_LOCATION] = data.location;
			
			dataToSave = [];	
			for each (value in data.locationsUnlocked) {
				dataToSave.push(value);
			}
			obj[SERIALIZED_LOCATIONS_UNLOCKED] = dataToSave.concat(); //clone
			
			return obj;
		}
		
		public static function unserialize(data:Object):PlayerData
		{
			var player:PlayerData = new PlayerData(),
				charactersUnlocked:* = data[SERIALIZED_CHARACTERS_UNLOCKED],
				locationsUnlocked:* = data[SERIALIZED_LOCATIONS_UNLOCKED],
				scores:* = data[SERIALIZED_SCORES],
				dataToCreate:*,
				obj:Object;
			
			player.playerName = data[SERIALIZED_PLAYER_NAME];
			player.characterName = data[SERIALIZED_CHARACTER_NAME];
			player.difficulty = data[SERIALIZED_DIFFICULTY];
			
			if (scores) {
				dataToCreate = new Vector.<IScoreObject>();
				for each (obj in scores) {
					dataToCreate.push(new ScoreObject(uint(obj.score), String(obj.locationName)));
				}
				
				player.scores = dataToCreate.concat(); //clone
			}
			
			if (charactersUnlocked) {
				dataToCreate = new Vector.<String>();
				for each (obj in charactersUnlocked) {
					dataToCreate.push(String(obj));
				}
				
				player.charactersUnlocked = dataToCreate.concat(); //clone
			}
			
			player.location = data[SERIALIZED_LOCATION];
			
			dataToCreate = null;
			if (locationsUnlocked) {
				dataToCreate = new Vector.<String>();
				for each (obj in locationsUnlocked) {
					dataToCreate.push(String(obj));
				}
				
				player.locationsUnlocked = dataToCreate.concat(); //clone
			}
			
			return player;
		}
		
		// ================================================================================================================================
		// PRIVATE
		// ================================================================================================================================
		
		private function cleanupScores():void
		{
			//sort array
			_scores.sort(ScoreObject.sortByScore);
			//max numbers
			if (_scores.length > MAX_SCORES) {
				_scores = _scores.slice(0, MAX_SCORES);
			}
		}
		
		// ================================================================================================================================
		// DESTRUCTOR
		// ================================================================================================================================
		
		public function destroy():void
		{
			_playerName = null;
			_characterName = null;
			if (_scores) {
				for each (var scoreObj:IDestroyable in _scores) {
					scoreObj.destroy();
				}
				_scores = null;
			}
			_charactersUnlocked = null;
			_location = null;
			_locationsUnlocked = null;
		}
	}
}